from cStringIO import StringIO
from ZPublisher.HTTPRequest import record
from types import InstanceType
from csv import DictWriter, DictReader
from DateTime.DateTime import DateTime, DateTimeError
from xml.dom import minidom 

## FIXME - Lots of cleanups needed in this module

import re
r_valid_id = re.compile( "^[a-zA-Z][a-zA-Z0-9\-_]*$" )




def isValidId( string ):
    """ Returns True if the specific string contains only basic alphanumeric characters, no symbols """
    
    if r_valid_id.match( string ): 
        return True
    else:
        return False
    
def evalExpression( string ):
    return eval(string, {}, {})
    

def cloneQuicklaunchDB(conn, original_id, new_id):
    """ Used to create a database for the Quicklaunch scripts """
    
    conn.query( "CREATE DATABASE %s" % new_id )
    
   
    description, rs_tables = conn.query( "SHOW TABLES FROM %s" % original_id )
    for row in rs_tables:
        table = row[0]
        if table == 'latestAnswers': continue
        
        conn.query( "CREATE TABLE %(new_id)s.%(table)s LIKE %(original_id)s.%(table)s" % locals() )
    

    conn.query( """
        CREATE VIEW %(new_id)s.latestAnswers AS 
        SELECT
            `answers`.`assessmentIdentity` AS `assessmentIdentity`,
            `answers`.`revision` AS `revision`,
            `answers`.`modelIdentity` AS `modelIdentity`,
            `answers`.`componentIdentity` AS `componentIdentity`,
            `answers`.`instantCreated` AS `instantCreated`,
            `answers`.`instantModified` AS `instantModified`,
            `answers`.`modifiedByUser` AS `modifiedByUser`,
            `answers`.`value` AS `value`,
            `answers`.`valueType` AS `valueType`,
            `answers`.`searchIndex` AS `searchIndex`,
            `answers`.`searchValue` AS `searchValue`
        FROM
            %(new_id)s.answers 
            INNER JOIN %(new_id)s.assessments ON `answers`.`assessmentIdentity` = `assessments`.`assessmentIdentity`
        WHERE
            `answers`.`revision` = `assessments`.`latestRevision`;
                 
    """ % locals() )
   
   #CREATE VIEW %(new_id)s.latestAnswers AS 
        #SELECT answers.*
        #FROM %(new_id)s.answers INNER JOIN %(new_id)s.assessments ON answers.assessmentIdentity = assessments.assessmentIdentity
        #WHERE answers.revision = assessments.latestRevision;
   
   
    return True        
    
def createUser( acl, username, password, roles=['Member'], domains='*' ):
    """ Creates and returns the specified user """
   
    acl._doAddUser( username, password, roles, domains )
    return acl.getUserById( username )
    
    
    

def getMemberPassword(member):
    """ Returns a members password (GRUF Only) """
    
    return member.getPassword()

def objectType(object):
    """ Wrapper for python type() keyword for use in python scripts """
    
    return type(object)

def isRecordSet(object):
    """ Determines if the specified object is a recordset """
    
    return type(object) is InstanceType and object.__class__ is record

def isList(object):
    """ Wrapper for python scripts to determine if object is a basic list type """
    
    return type(object) in (list,tuple)

def makeList(object):
    """ Wraps an object in a list if it isn't already """
    
    if type(object) in (list, tuple):
        return list(object)
    else:
        return [object]

def renderDOT( dot, outputType='png' ):
    """ Renders a graphviz 'dot' file into an image file """
    
    pass # TODO


def recordException( error_log ):
    """ Wrapper to record exception information in the error log, getting around PythonScript exceptions 
        Gets info for the current exception when called in an except: block.
    
        param:      error_log - A Reference to the site error log        
        
        Returns: The URL to the exception info page.
    """
    
    import sys
    info = sys.exc_info()
    
    return error_log.raising( info )



def parseDate( string ):
    """ 
        Parses a date string and returns a DateTime Object, or None if it could not be parsed 
        (Designed for use in Page Templates, where lack of proper exception handling
         makes catching date errors very messy)    
    """
    
    if not string:   # If no string is specified, return a None
        return None
    
    try:
        return DateTime( string )
    except DateTimeError:  
        # Could not parse the date string, return None
        return None
        

def parseCSV( data ):
    """ Parses a CSV and returns a list of dicts """
    
    results = []
    reader = DictReader( data )
    for row in reader:
        results.append( row )
        
    return results        


def renderCSV( fields, data, renderHeader = False ):
    """ Renders a CSV with the specified fields from 'data' 
    
        fields: list of keys
        data: list of dictionaries
    """
    
    out = StringIO()
    
    if renderHeader:
        print >> out, '"' + '","'.join( fields ) + '"'
    
    writer = DictWriter( out, fields, extrasaction='ignore' )
    writer.writerows( data )
    return out.getvalue()
    


def serializeRequest(form, recordName=None, skip=[]):
    """ 
        Serializes a request/form into hidden fields 
        i.e. {key:value}
        becomes
            <input name="key" value="value'"/>
    """
    
    out = StringIO()
    
    recordPrefix = recordPostfix = ""
    
    if recordName:
        recordPrefix = "%s." % recordName
        recordPostfix = ":record"
    
    
    for key, value in form.items():
        
        if key in skip: 
            continue
        
        # Simple key => value pair
        if type( value ) in ( str, unicode, int, float, long, complex ):
            print >> out, '<input type="hidden" name="%(recordPrefix)s%(key)s%(recordPostfix)s" value="%(value)s"/>\n' % locals()
            
        # key => [value] pair (List of values)
        elif type(value) in (list, tuple):
            for item in value:
                print >> out, '<input type="hidden" name="%(recordPrefix)s%(key)s:list%(recordPostfix)s" value="%(item)s"/>\n' % locals()
                
        # Recordset- key => {key:value, ...}
        elif type(value) is dict or type(value) is InstanceType and value.__class__ is record:
            
            # RecordSets are an entire list of key-value pairs in themselves, and we should be able to render them recursively.
            print >> out, serializeRequest( dict(value), recordName=key )
                        
        else:
            
            # Unknown type, we can't serialize it
            raise "Cannot serialize %s" % `value`
            
                   
    return out.getvalue()                   
        
        
def urlquote( url ):
    import urllib
    return urllib.quote( url )        
                
        
class ReprString:
    def __init__(self, string):
        self.string = string
            
    def __repr__(self):
        return self.string
    
    
        